﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Mapping;
namespace NHibernate.Audit
{
    public class MappingsCache 
    {

        public const string BASIC_ENTITY_1 = "NHibernate.Audit.Mappings.Basic.BasicTestEntity1";
        public const string REVISION_INFO = "NHibernate.Audit.Mappings.Basic.RevisionInfo";
        public const string BASIC_ENTITY_1_MANUAL_AUDIT = "NHibernate.Audit.Mappings.Basic.BasicTestEntity1Manual_Audit";

        private Dictionary<string, byte[]> cache = new Dictionary<string, byte[]>();

        public MappingsCache Initialize()
        {
            var cfg = ConfigureNHibernate();
            SerializeMappings(cfg);
            return this;
        }

        private Configuration ConfigureNHibernate()
        {
            var cfg = new Configuration();
            cfg.Configure("hibernate.test.cfg.xml");
            cfg.AddAssembly(this.GetType().Assembly);
            return cfg;
        }

        private void SerializeMappings(Configuration configuration)
        {
            foreach (var clazz in configuration.ClassMappings)
                SerializeMapping(clazz);
        }

        private void SerializeMapping(PersistentClass clazz)
        {
            var data = NHibernate.Util.SerializationHelper.Serialize(clazz);
            var name = GetEntityOrClassName(clazz);
            cache.Add(name, data);
        }

        private PersistentClass DeserializeMapping(string name)
        {
            byte[] data;
            PersistentClass clazz;
            data = cache[name];
            clazz = (PersistentClass)NHibernate.Util.SerializationHelper.Deserialize(data);
            return clazz;
        }

        private string GetEntityOrClassName(PersistentClass clazz)
        {
            return string.IsNullOrEmpty(clazz.EntityName) ? clazz.ClassName : clazz.EntityName;
        }

        public IEnumerable<string> Mappings { 
            get { return cache.Keys.AsEnumerable(); } 
        }
        
        public PersistentClass GetMapping(string entityOrClassName)
        {
            return DeserializeMapping(entityOrClassName);
        }

        public void AddMappingToConfiguration(Configuration configuration, string entityOrClassName)
        {

            switch (entityOrClassName)
            {
                case BASIC_ENTITY_1:
                    configuration.AddResource("NHibernate.Audit.Mappings.Basic.BasicTestEntity1.hbm.xml", this.GetType().Assembly);
                    break;
                case REVISION_INFO:
                    configuration.AddResource("NHibernate.Audit.Mappings.Basic.RevisionEntity.hbm.xml", this.GetType().Assembly);
                    break;
                case BASIC_ENTITY_1_MANUAL_AUDIT:
                    configuration.AddResource("NHibernate.Audit.Mappings.Basic.BasicTestEntity1Manual_Audit.hbm.xml", this.GetType().Assembly);
                    break;
                default:
                    throw new NotSupportedException();
            }
        }

    }
}
